﻿using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace Generador_Terreno
{
    [ContentProcessor]
    class Generador_Cielo : ContentProcessor<Texture2DContent, ModelContent>
    {
        const float cylinderSize = 3650;
        const int cylinderSegments = 4;
        const float texCoordTop = 1.0f;
        const float texCoordBottom =2.0f;
        string CieloTextura;


        /// <summary>
        /// Genera la geometria celestepara la textura del cielo de entrada.
        /// </summary>
        public override ModelContent Process(Texture2DContent input, ContentProcessorContext context)
        {
            MeshBuilder builder = MeshBuilder.StartMesh("sky");

            // Crea la lista de vertices superiores e inferiores de la forma que queramos el cielo.
            List<int> topVertices = new List<int>();
            List<int> bottomVertices = new List<int>();

            float angle = MathHelper.PiOver4;

            for (int i = 0; i < cylinderSegments; i++)
            {
                float x = (float)Math.Cos(angle) * cylinderSize;
                float z = (float)Math.Sin(angle) * cylinderSize;

                topVertices.Add(builder.CreatePosition(x, cylinderSize, z));
                bottomVertices.Add(builder.CreatePosition(x, -cylinderSize, z));
                angle = angle + MathHelper.PiOver2;
            }

            // Creamos 2 centros vertices para cerrar el cielo por arriba y por abajo.
            int topCenterVertex = builder.CreatePosition(0, cylinderSize * 2, 0);
            int bottomCenterVertex = builder.CreatePosition(0, -cylinderSize * 2, 0);

            BasicMaterialContent material = new BasicMaterialContent();
            string directory = Path.GetDirectoryName(input.Identity.SourceFilename);
            CieloTextura = Path.GetFileName(input.Identity.SourceFilename);
            string texture = Path.Combine(directory, CieloTextura);
            material.Texture = new ExternalReference<TextureContent>(texture);

            builder.SetMaterial(material);       

            // Crea un canal de vertice de union para la coordinacion de las texturas.
            int texCoordId = builder.CreateVertexChannel<Vector2>(VertexChannelNames.TextureCoordinate(0));

            // Crea los triangulos para hacer nuestro cielo.
            for (int i = 0; i < cylinderSegments; i++)
            {
                int j = (i + 1) % cylinderSegments;

                //Calcula las coordenadas de la texturas para el segmento de la figura.
                float u1 = (float)i / (float)cylinderSegments;
                float u2 = (float)(i + 1) / (float)cylinderSegments;

                // Juntamos 2 triangulos para formar un lado de la figura.
                AddVertex(builder, topVertices[i], texCoordId, u1, texCoordTop);
                AddVertex(builder, topVertices[j], texCoordId, u2, texCoordTop);
                AddVertex(builder, bottomVertices[i], texCoordId, u1, texCoordBottom);

                AddVertex(builder, topVertices[j], texCoordId, u2, texCoordTop);
                AddVertex(builder, bottomVertices[j], texCoordId, u2, texCoordBottom);
                AddVertex(builder, bottomVertices[i], texCoordId, u1, texCoordBottom);

                // Abanico superior para cubrir el cielo completamente.
                AddVertex(builder, topCenterVertex, texCoordId, u1, 0);
                AddVertex(builder, topVertices[j], texCoordId, u2, texCoordTop);
                AddVertex(builder, topVertices[i], texCoordId, u1, texCoordTop);

                // Abanico inferior para cubrir el cielo.
                AddVertex(builder, bottomCenterVertex, texCoordId, u1, 1);
                AddVertex(builder, bottomVertices[i], texCoordId, u1, texCoordBottom);
                AddVertex(builder, bottomVertices[j], texCoordId, u2, texCoordBottom);
            }

            // Creamos el objeto saliente.
           

            // Se lo pasamos al Proceso principal para convertir la malla generada
            MeshContent skyMesh = builder.FinishMesh();

            return context.Convert<MeshContent, ModelContent>(skyMesh, "ModelProcessor");
        }


        /// <summary>
        /// Funcion auxiliar que añade un triangulo al constructor de la malla, junto con la textura asociada a la coordenada.
        /// </summary>
        static void AddVertex(MeshBuilder builder, int vertex, int texCoordId, float u, float v)
        {
            builder.SetVertexChannelData(texCoordId, new Vector2(u, v));

            builder.AddTriangleVertex(vertex);
        }
    }
}
